package tabletask

import (
	"strings"
	"time"
	"cvevulner/cve-timed-task/util"
	"github.com/antchfx/htmlquery"
	"github.com/astaxie/beego/logs"
	"github.com/pkg/errors"
)

type XpathList struct {
	NvdScore          string
	CveLevel          string
	CveDesc           string
	RepairTime        string
	VectorValue       string
	AttackVector      string
	AccessVector      string
	AttackComplexity  string
	AccessComplexity  string
	PrivilegeRequired string
	UserInteraction   string
	Scope             string
	Confidentiality   string
	Integrity         string
	Availability      string
	Authentication    string
	ScoreType         string
}

// Crawling Grab cve specific information
func Crawling(url string) (XpathList, error) {
	xpathList := XpathList{}

	if url == "" || !strings.Contains(url, "http") {
		return xpathList, errors.New("url is not standardized")
	}

	html, err := util.UrlToHTML(url)
	if err != nil {
		return xpathList, err
	}
	//xpathList.CveDesc
	nodes, err := htmlquery.QueryAll(html, "//*[@id=\"vulnDetailTableView\"]//tr/td/div/div[1]/p[1]/text()")
	if err != nil {
		return xpathList, err
	} else {
		if len(nodes) > 0 {
			cveDesc := htmlquery.InnerText(nodes[0])
			if cveDesc == "N/A" {
				xpathList.CveDesc = ""
			} else {
				xpathList.CveDesc = cveDesc
			}
		}
	}
	//xpathList.RepairTime
	nodes, err = htmlquery.QueryAll(html, "//*[@data-testid=\"vuln-published-on\"]/text()")
	if err != nil {
		return xpathList, err
	} else {
		if len(nodes) > 0 {
			repairTime := htmlquery.InnerText(nodes[0])
			if repairTime != "" {
				if repairTime == "N/A" {
					xpathList.RepairTime = ""
				} else {
					w, err := time.ParseInLocation("01/02/2006", repairTime, time.Local)
					if err == nil {
						xpathList.RepairTime = w.Format("2006-01-02 15:04:05")
					} else {
						logs.Error(err.Error())
					}
				}
			}
		}
	}
	xpathList.ScoreType = "v3.0"

	nodes, err = htmlquery.QueryAll(html, "//*[@id=\"nistV3MetricHidden\"]/@value")
	if err != nil {
		return xpathList, err
	}
	if len(nodes) == 0 {
		nodes, err = htmlquery.QueryAll(html, "//*[@id=\"cnaV3MetricHidden\"]/@value")
		if err != nil {
			return xpathList, err
		}
	}
	if len(nodes) > 0 {
		value := htmlquery.SelectAttr(nodes[0], "value")
		if value != "" {
			childHtml, err := htmlquery.Parse(strings.NewReader(value))
			if err != nil {
				return xpathList, err
			}

			//xpathList.CveLevel
			nodes, err = htmlquery.QueryAll(childHtml, "//*[@data-testid=\"vuln-cvssv3-base-score-severity\"]/text()")
			if err != nil {
				return xpathList, err
			}
			if len(nodes) > 0 {
				cl := htmlquery.InnerText(nodes[0])
				if len(cl) > 0 {
					cl = strings.TrimSpace(cl)
					xpathList.CveLevel = strings.ToUpper(cl[:1]) + strings.ToLower(cl[1:])
				}
			}

			//xpathList.NvdScore
			nodes, err = htmlquery.QueryAll(childHtml, "//*[@data-testid=\"vuln-cvssv3-base-score\"]/text()")
			if err != nil {
				return xpathList, err
			}
			if len(nodes) > 0 {
				xpathList.NvdScore = strings.TrimSpace(htmlquery.InnerText(nodes[0]))
			}
			//xpathList.VectorValue
			nodes, err = htmlquery.QueryAll(childHtml, "//*[@data-testid=\"vuln-cvssv3-vector\"]/text()")
			if err != nil {
				return xpathList, err
			}
			if len(nodes) > 0 {
				vv := htmlquery.InnerText(nodes[0])
				vv = strings.Replace(vv, "(", "", -1)
				vv = strings.Replace(vv, ")", "", -1)
				xpathList.VectorValue = strings.TrimSpace(vv)
			}
			//xpathList.AttackVector
			nodes, err = htmlquery.QueryAll(childHtml, "//*[@data-testid=\"vuln-cvssv3-av\"]/text()")
			if err != nil {
				return xpathList, err
			}
			if len(nodes) > 0 {
				xpathList.AttackVector = strings.TrimSpace(htmlquery.InnerText(nodes[0]))
			}
			//xpathList.AttackComplexity
			nodes, err = htmlquery.QueryAll(childHtml, "//*[@data-testid=\"vuln-cvssv3-ac\"]/text()")
			if err != nil {
				return xpathList, err
			}
			if len(nodes) > 0 {
				xpathList.AttackComplexity = strings.TrimSpace(htmlquery.InnerText(nodes[0]))
			}
			//xpathList.PrivilegeRequired
			nodes, err = htmlquery.QueryAll(childHtml, "//*[@data-testid=\"vuln-cvssv3-pr\"]/text()")
			if err != nil {
				return xpathList, err
			}
			if len(nodes) > 0 {
				xpathList.PrivilegeRequired = strings.TrimSpace(htmlquery.InnerText(nodes[0]))
			}

			//xpathList.UserInteraction
			nodes, err = htmlquery.QueryAll(childHtml, "//*[@data-testid=\"vuln-cvssv3-ui\"]/text()")
			if err != nil {
				return xpathList, err
			}
			if len(nodes) > 0 {
				xpathList.UserInteraction = strings.TrimSpace(htmlquery.InnerText(nodes[0]))
			}
			//xpathList.Scope
			nodes, err = htmlquery.QueryAll(childHtml, "//*[@data-testid=\"vuln-cvssv3-s\"]/text()")
			if err != nil {
				return xpathList, err
			}
			if len(nodes) > 0 {
				xpathList.Scope = strings.TrimSpace(htmlquery.InnerText(nodes[0]))
			}
			//xpathList.Confidentiality
			nodes, err = htmlquery.QueryAll(childHtml, "//*[@data-testid=\"vuln-cvssv3-c\"]/text()")
			if err != nil {
				return xpathList, err
			}
			if len(nodes) > 0 {
				xpathList.Confidentiality = strings.TrimSpace(htmlquery.InnerText(nodes[0]))
			}
			//xpathList.Integrity
			nodes, err = htmlquery.QueryAll(childHtml, "//*[@data-testid=\"vuln-cvssv3-i\"]/text()")
			if err != nil {
				return xpathList, err
			}
			if len(nodes) > 0 {
				xpathList.Integrity = strings.TrimSpace(htmlquery.InnerText(nodes[0]))
			}
			//xpathList.Integrity
			nodes, err = htmlquery.QueryAll(childHtml, "//*[@data-testid=\"vuln-cvssv3-a\"]/text()")
			if err != nil {
				return xpathList, err
			}
			if len(nodes) > 0 {
				xpathList.Availability = strings.TrimSpace(htmlquery.InnerText(nodes[0]))
			}
		}
	} else {
		nodes, err = htmlquery.QueryAll(html, "//*[@id=\"nistV2MetricHidden\"]/@value")
		if len(nodes) > 0 {
			value := htmlquery.SelectAttr(nodes[0], "value")
			if value != "" {
				childHtml, err := htmlquery.Parse(strings.NewReader(value))
				if err != nil {
					return xpathList, err
				}
				xpathList.ScoreType = "v2.0"
				//xpathList.CveLevel
				nodes, err = htmlquery.QueryAll(childHtml, "//*[@data-testid=\"vuln-cvssv2-base-score-severity\"]/text()")
				if err != nil {
					return xpathList, err
				}
				if len(nodes) > 0 {
					cl := htmlquery.InnerText(nodes[0])
					if len(cl) > 0 {
						cl = strings.TrimSpace(cl)
						xpathList.CveLevel = strings.ToUpper(cl[:1]) + strings.ToLower(cl[1:])
					}
				}

				//xpathList.NvdScore
				nodes, err = htmlquery.QueryAll(childHtml, "//*[@data-testid=\"vuln-cvssv2-base-score\"]/text()")
				if err != nil {
					return xpathList, err
				}
				if len(nodes) > 0 {
					xpathList.NvdScore = strings.TrimSpace(htmlquery.InnerText(nodes[0]))
				}

				//xpathList.VectorValue
				nodes, err = htmlquery.QueryAll(childHtml, "//*[@data-testid=\"vuln-cvssv2-vector\"]/text()")
				if err != nil {
					return xpathList, err
				}
				if len(nodes) > 0 {
					vv := htmlquery.InnerText(nodes[0])
					vv = strings.Replace(vv, "(", "", -1)
					vv = strings.Replace(vv, ")", "", -1)
					xpathList.VectorValue = strings.TrimSpace(vv)
				}

				//xpathList.AccessVector
				nodes, err = htmlquery.QueryAll(childHtml, "//*[@data-testid=\"vuln-cvssv2-av\"]/text()")
				if err != nil {
					return xpathList, err
				}
				if len(nodes) > 0 {
					xpathList.AccessVector = strings.TrimSpace(htmlquery.InnerText(nodes[0]))
				}

				//xpathList.AccessComplexity
				nodes, err = htmlquery.QueryAll(childHtml, "//*[@data-testid=\"vuln-cvssv2-ac\"]/text()")
				if err != nil {
					return xpathList, err
				}
				if len(nodes) > 0 {
					xpathList.AccessComplexity = strings.TrimSpace(htmlquery.InnerText(nodes[0]))
				}

				//xpathList.Authentication
				nodes, err = htmlquery.QueryAll(childHtml, "//*[@data-testid=\"vuln-cvssv2-au\"]/text()")
				if err != nil {
					return xpathList, err
				}
				if len(nodes) > 0 {
					xpathList.Authentication = strings.TrimSpace(htmlquery.InnerText(nodes[0]))
				}

				//xpathList.Confidentiality
				nodes, err = htmlquery.QueryAll(childHtml, "//*[@data-testid=\"vuln-cvssv2-c\"]/text()")
				if err != nil {
					return xpathList, err
				}
				if len(nodes) > 0 {
					xpathList.Confidentiality = strings.TrimSpace(htmlquery.InnerText(nodes[0]))
				}

				//xpathList.Integrity
				nodes, err = htmlquery.QueryAll(childHtml, "//*[@data-testid=\"vuln-cvssv2-i\"]/text()")
				if err != nil {
					return xpathList, err
				}
				if len(nodes) > 0 {
					xpathList.Integrity = strings.TrimSpace(htmlquery.InnerText(nodes[0]))
				}

				//xpathList.Availability
				nodes, err = htmlquery.QueryAll(childHtml, "//*[@data-testid=\"vuln-cvssv2-a\"]/text()")
				if err != nil {
					return xpathList, err
				}
				if len(nodes) > 0 {
					xpathList.Availability = strings.TrimSpace(htmlquery.InnerText(nodes[0]))
				}
			}
		}
	}

	return xpathList, nil
}
